from enum import Enum
from typing import  List
from .DataSource import FileDataSource, LogLine
from .Decoder import Decoder
from .Renderer import Renderer
from src.LogPlayer.entity.LogLine import LogLine
from src.LogPlayer.entity.Frame import Frame
from src.LogPlayer.utils.Worker import Message, Worker
from PySide2.QtCore import Signal, Slot, QObject
from src.LogPlayer.utils.CommonUtil import curTimeMills

class STATE(Enum):
    IDLE = 0
    INITIALIZED = 1
    PREPARING = 2
    PREPARED = 3
    STARTED = 4
    PAUSED = 5
    STOPPED = 6
    SEEKING = 7
    PLAYBACK_COMPLETED = 8
    END = 9

# 用来做各个模块间的时间同步 以及判断是否需要丢帧
class TimeBase:
    realTimeAnchor: int = curTimeMills()
    playedTimeAnchor: int = 0
    currentTime: int

    def updateAnchor(self, playedTime):
        self.realTimeAnchor = curTimeMills()
        self.playedTimeAnchor = playedTime

    def calcDelay(self, playedTimestamp) -> int:
        return playedTimestamp - self.playedTimeAnchor + self.realTimeAnchor - curTimeMills()

class Player(QObject):
    preparedSignal = Signal(int)
    timeBase: TimeBase = TimeBase()
    _onBufferDecodedSignal = Signal(Frame)
    def __init__(self):
        super().__init__()
        self.state = STATE.IDLE
        self.dataSource = None
        self.decoder = None
        self.renderer = None
        self.onPreparedListener = None
        self.onPlayCompleteListener = None
        # global globalWorker
        # print('globalWorker = ', globalWorker)
        # if globalWorker is None:
        #     globalWorker = Worker()

        print('preparedSignal:', self.preparedSignal.connect)
        self.preparedSignal.connect(self.onPrepared)
        self._onBufferDecodedSignal.connect(self._onBufferDecoded)

        self._worker = Worker()
        self._worker.start()


    def setDataSource(self, path: str | List[str]):
        if self.state != STATE.IDLE:
            print('setDataSource state err')
            return
        self.dataSource = FileDataSource(path)
        self.state = STATE.INITIALIZED

    def prepare(self):
        if self.state != STATE.INITIALIZED:
            print('prepare state err')
            return
        msg = Message()
        msg.onBackground = self.dataSource.prepare
        msg.onFinish = self.preparedSignal
        self._worker.post(msg)
        self.state = STATE.PREPARING

    @Slot(int)
    def onPrepared(self, result: int):
        if result == 0:
            print("prepared 000")
            self.state = STATE.PREPARED
            self.decoder = Decoder()
            self.renderer = Renderer()
            if self.onPreparedListener:
                self.onPreparedListener()
        else:
            print("prepared failed")

    def setWindow(self, type: int, callback: callable):
        if self.renderer:
            self.renderer.registerRenderers(type, callback)


    def play(self):
        if not self.state in [STATE.PREPARED, STATE.PAUSED, STATE.STOPPED,
                              STATE.PLAYBACK_COMPLETED]:
            print('play state err')
            return -1
        self._playForTest()


    # 调测用
    def _playForTest(self):
        fileDataSource: FileDataSource = self.dataSource
        self.timeBase.updateAnchor(fileDataSource.packets[0].timeStamp)
        for logLine in fileDataSource.packets:
            msg: Message = Message()
            msg.arg = logLine
            msg.onBackground = self._decodeForTest
            msg.onFinish = self._onBufferDecodedSignal
            self._worker.postDelay(msg, self.timeBase.calcDelay(logLine.timeStamp))
        pass

    def _decodeForTest(self, logLine:LogLine) -> Frame:
        print(logLine)
        return self.decoder.decode(logLine)

    @Slot(Frame)
    def _onBufferDecoded(self, frame: Frame):
        self.renderer.render(frame)

    def pause(self):
        pass

    def stop(self):
        pass

    def reset(self):
        if not self.state in [STATE.IDLE, STATE.INITIALIZED, STATE.PREPARED, STATE.STARTED, STATE.PAUSED, STATE.STOPPED,
                              STATE.PLAYBACK_COMPLETED]:
            print('reset state err')
            return -1
        if self.dataSource:
            self.dataSource.release()
            del self.dataSource
        self.state = STATE.IDLE
        # TODO other resources

    def release(self):
        self.state = STATE.END
        if self.dataSource:
            self.dataSource.release()
        # TODO other resources

    def getCurrentState(self) -> STATE:
        return self.state

    def getDuration(self) -> int:
        if self.state in [STATE.IDLE, STATE.INITIALIZED, STATE.END]:
            return 0
        return self.dataSource.getDuration()

    def getStartTime(self) -> int:
        if self.state in [STATE.IDLE, STATE.INITIALIZED, STATE.END]:
            return 0
        return self.dataSource.getStartTime()

    def getEndTime(self) -> int:
        if self.state in [STATE.IDLE, STATE.INITIALIZED, STATE.END]:
            return 0
        return self.dataSource.getEndTime()

    def setOnPreparedListener(self, listener):
        self.onPreparedListener = listener

    def setOnPlayCompleteListener(self, listener):
        self.onPlayCompleteListener = listener

    def onFirstFrameRendered(self, logLine: LogLine):
        self.timeBase.updateAnchor(logLine.timeStamp)